home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / MacPerl ƒ / Perl Source ƒ / Perl / SubLaunch.c < prev    next >
Text File  |  1993-12-20  |  9KB  |  376 lines

  1. /*********************************************************************
  2. Project    :    SubLaunch        -    Call ToolServer
  3. File        :    SubLaunch.c        -    The code
  4. Author    :    Matthias Neeracher
  5. Started    :    06Dec91                                Language    :    MPW C/C++
  6. Modified    :    06Dec91    MN    
  7.                 07Mar92    MN    
  8.                 25Nov93    MN    Mo' better spin
  9. Last        :    25Nov93
  10.  
  11. Copyright (c) 1991, 1992 Matthias Neeracher
  12.  
  13.     You may distribute under the terms of the Perl Artistic License,
  14.     as specified in the README file.
  15.  
  16. *********************************************************************/
  17.  
  18. /* We need glue for Gestalt, but not for the rest of the stuff */
  19.  
  20. #include <GestaltEqu.h>
  21. #include "SubLaunch.h"
  22. #include <TFileSpec.h>
  23. #include <GUSI.h>
  24.  
  25. #include <Processes.h>
  26. #include <AppleEvents.h>
  27. #include <CursorCtl.h>
  28. #include <Resources.h>
  29. #include <QuickDraw.h>
  30. #include <Folders.h>
  31. #include <Errors.h>
  32. #include <Script.h>
  33.  
  34. #include <string.h>
  35.  
  36. #define FAILOSERR(call)    if (err = call)    return err
  37. #define ToolServer    'MPSX'
  38.  
  39. /* The following stuff is adapted from Jens Peter Alfke's SignatureToApp code */
  40.  
  41. static OSErr ToolServerRunning(ProcessSerialNumber *psn)
  42. {
  43.     OSErr err;
  44.     ProcessInfoRec info;
  45.     
  46.     psn->highLongOfPSN = 0;
  47.     psn->lowLongOfPSN  = kNoProcess;
  48.     do    {
  49.         FAILOSERR(GetNextProcess(psn));
  50.         info.processInfoLength     = sizeof(info);
  51.         info.processName             = nil;
  52.         info.processAppSpec         = nil;
  53.         FAILOSERR(GetProcessInformation(psn,&info));
  54.     } while(info.processSignature != ToolServer);
  55.  
  56.     *psn = info.processNumber;
  57.     
  58.     return noErr;
  59. }
  60.  
  61. static OSErr GetSysVolume(short *vRefNum)
  62. {
  63.     long dir;
  64.     
  65.     return FindFolder(kOnSystemDisk, kSystemFolderType, false, vRefNum, &dir);
  66. }
  67.  
  68.  
  69. static OSErr GetIndVolume(short index, short *vRefNum)
  70. {
  71.     OSErr             err;
  72.     ParamBlockRec     pb;
  73.     
  74.     pb.volumeParam.ioNamePtr     = nil;
  75.     pb.volumeParam.ioVolIndex     = index;
  76.     
  77.     FAILOSERR(PBGetVInfoSync(&pb));
  78.     
  79.     *vRefNum = pb.volumeParam.ioVRefNum;
  80.     
  81.     return noErr;
  82. }
  83.  
  84. static OSErr VolHasDesktopDB(short vRefNum, Boolean * hasDesktop)
  85. {
  86.     OSErr                         err;
  87.     HParamBlockRec             pb;
  88.     GetVolParmsInfoBuffer     info;
  89.     
  90.     pb.ioParam.ioNamePtr     = nil;
  91.     pb.ioParam.ioVRefNum     = vRefNum;
  92.     pb.ioParam.ioBuffer         = (Ptr)&info;
  93.     pb.ioParam.ioReqCount     = sizeof(GetVolParmsInfoBuffer);
  94.     
  95.     FAILOSERR(PBHGetVolParmsSync(&pb));
  96.  
  97.     *hasDesktop = (info.vMAttrib & (1 << bHasDesktopMgr))!=0;
  98.     
  99.     return noErr;
  100. }
  101.  
  102. static OSErr FindAppOnVolume(short vRefNum, FSSpec *file)
  103. {
  104.     OSErr     err;
  105.     DTPBRec     pb;
  106.     
  107.     /* Get Acess path to Desktop database on this volume */
  108.     
  109.     pb.ioVRefNum         = vRefNum;
  110.     pb.ioNamePtr         = nil;
  111.     FAILOSERR(PBDTGetPath(&pb));
  112.     
  113.     pb.ioIndex             = 0;
  114.     pb.ioFileCreator     = ToolServer;
  115.     pb.ioNamePtr         = file->name;
  116.     switch (err = PBDTGetAPPLSync(&pb))    {
  117.     case noErr:
  118.         file->vRefNum     = vRefNum;
  119.         file->parID     = pb.ioAPPLParID;
  120.     
  121.         return noErr;
  122.     case fnfErr:
  123.         return afpItemNotFound;                        /* Bug in PBDTGetAPPL            */
  124.     default:
  125.         return err;
  126.     }
  127. }
  128.  
  129. /* LaunchApplication in 32 bit everything environment    */
  130.  
  131. pascal OSErr WrappedLaunchApplication(const LaunchParamBlockRec *LaunchParams);
  132.  
  133. static OSErr LaunchIt(const FSSpecPtr fileSpec, ProcessSerialNumber *psn )
  134. {
  135.     OSErr                     err;
  136.     LaunchParamBlockRec     pb;
  137.     
  138.     pb.launchBlockID             = extendedBlock;
  139.     pb.launchEPBLength         = extendedBlockLen;
  140.     pb.launchFileFlags         = launchNoFileFlags;
  141.     pb.launchControlFlags    = launchContinue | launchNoFileFlags | launchDontSwitch;
  142.     pb.launchAppSpec             = fileSpec;
  143.     pb.launchAppParameters    = nil;
  144.     
  145.     FAILOSERR(WrappedLaunchApplication(&pb));
  146.  
  147.     *psn = pb.launchProcessSN;
  148.     
  149.     return noErr;
  150. }
  151.  
  152. /* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
  153. static OSErr LaunchToolServer(ProcessSerialNumber *psn)
  154. {
  155.     OSErr     err;
  156.     short     sysVRefNum, vRefNum, index;
  157.     FSSpec     file;
  158.     Boolean     hasDesktopDB;
  159.     
  160.     /* See if ToolServer is already running:                    */
  161.     err    = ToolServerRunning(psn);
  162.     
  163.     if    (err != procNotFound)
  164.         return err;
  165.     
  166.     /* Not running, try to launch it */
  167.     
  168.     FAILOSERR(GetSysVolume(&sysVRefNum));
  169.     vRefNum     = sysVRefNum;
  170.     for (index = 0; !err; err = GetIndVolume(++index,&vRefNum)) {
  171.         if (!index || vRefNum != sysVRefNum) {
  172.             FAILOSERR(VolHasDesktopDB(vRefNum,&hasDesktopDB));
  173.             if (hasDesktopDB)    
  174.                 switch (err = FindAppOnVolume(vRefNum, &file))    {
  175.                 case noErr:
  176.                     return LaunchIt(&file,psn);
  177.                 case afpItemNotFound:
  178.                     break;
  179.                 default:
  180.                     return err;
  181.                 }
  182.         }
  183.     }
  184.     switch (err)    {
  185.     case nsvErr:
  186.     case afpItemNotFound:
  187.         return fnfErr;
  188.     default:
  189.         return err;
  190.     }
  191. }
  192.  
  193. typedef enum {
  194.     dontKnow,
  195.     canRun,
  196.     cantRun
  197. } featureCheck;
  198.  
  199. static featureCheck    requiredFeatures    =    dontKnow;
  200.  
  201. #define HASBIT(bit) (answer&(1<<bit))
  202. #define GESTALT(sel) !Gestalt(sel, &answer)
  203.  
  204. OSErr ValidateFeatures()
  205. {
  206.     long answer;
  207.     
  208.     switch (requiredFeatures)    {
  209.     case canRun:
  210.         return noErr;
  211.     case cantRun:
  212.         return gestaltUnknownErr;
  213.     case dontKnow:
  214.         if (    GESTALT(gestaltAppleEventsAttr)                            && 
  215.                     HASBIT(gestaltAppleEventsPresent)                     &&
  216.                  GESTALT(gestaltFindFolderAttr)                            &&
  217.                     HASBIT(gestaltFindFolderPresent)                     &&
  218.                 GESTALT(gestaltOSAttr)                                        &&
  219.                     HASBIT(gestaltLaunchCanReturn)                        &&
  220.                     HASBIT(gestaltLaunchFullFileSpec)                    &&
  221.                     HASBIT(gestaltLaunchControl)                            &&
  222.                 GESTALT(gestaltFSAttr)                                        &&
  223.                     HASBIT(gestaltHasFSSpecCalls)
  224.         )
  225.             requiredFeatures    =    canRun;
  226.         else
  227.             requiredFeatures     =     cantRun;
  228.         
  229.         return ValidateFeatures();
  230.     }
  231. }
  232.  
  233. #define FAILOSERR(call)    if (err = call)    return err
  234.  
  235. /* Create a temporary file in the temp folder. 
  236. */
  237. OSErr    FSpMakeTempFile(FSSpec * desc)
  238. {
  239.     static int    id    =    0;
  240.  
  241.     OSErr            err;
  242.     
  243.     FAILOSERR(FindFolder(kOnSystemDisk, 'temp', true, &desc->vRefNum, &desc->parID));
  244.     
  245.     *((long *) desc->name)        =    '\007tmp';
  246.     
  247.     do {
  248.         desc->name[4]    =    id / 1000     % 10 + '0';
  249.         desc->name[5]    =    id / 100        % 10 + '0';
  250.         desc->name[6]    =    id / 10        % 10 + '0';
  251.         desc->name[7]    =    id             % 10 + '0';
  252.         
  253.         ++id;
  254.         
  255.         err = HCreate(desc->vRefNum, desc->parID, desc->name, 'TEMP', 'TEXT');
  256.     } while (err == dupFNErr);
  257.     
  258.     return err;
  259. }
  260.             
  261. pascal Boolean SubLaunchIdle(EventRecord * ev, long * sleep, RgnHandle *)
  262. {
  263.     SpinCursor(1);
  264.     
  265.     if (ev->what == kHighLevelEvent)
  266.         if (AEProcessAppleEvent(ev)) 
  267.             return true;
  268.         
  269.     *sleep    =    10;
  270.     
  271.     return false;
  272. }
  273.  
  274. static char * Fragments[] = {
  275.     "Directory \'",
  276.     "\'; Begin; ",
  277.     "; End<\'",
  278.     "\' >\'",
  279.     "\' ≥\'",
  280.     "\'\n",
  281.     "Dev:Null"
  282. };
  283.  
  284. #define BEGIN_TEXT    Fragments[0]
  285. #define DIRSET_TEXT    Fragments[1]
  286. #define END_TEXT        Fragments[2]
  287. #define STDOUT_TEXT    Fragments[3]
  288. #define STDERR_TEXT    Fragments[4]
  289. #define TERM_TEXT        Fragments[5]
  290. #define DEVNULL_TEXT    Fragments[6]
  291. #define DEVSTRING(dev)                     \
  292.     if (dev)                                 \
  293.         segment = FSp2FullPath(dev);     \
  294.     else                                         \
  295.         segment = DEVNULL_TEXT
  296.         
  297. /* Execute the command. Any of the files may be set to NULL */
  298. OSErr SubLaunch(char * commandline, FSSpec * input, FSSpec * output, FSSpec * error)
  299. {
  300.     OSErr                        err;
  301.     Boolean                    same;
  302.     ProcessSerialNumber    psn;
  303.     ProcessSerialNumber    me;
  304.     AppleEvent                cmd;
  305.     AppleEvent                reply;
  306.     AEAddressDesc            addr;
  307.     acurHandle                acur;
  308.     Handle                    text;
  309.     char *                    segment;
  310.     FSSpec                    vol;
  311.     
  312.     /* Check if the system is sexy enough */
  313.     FAILOSERR(ValidateFeatures());
  314.     
  315.     /* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
  316.     FAILOSERR(LaunchToolServer(&psn));
  317.     
  318.     /* It would be disastrous to send the event to ourselves (I know: I tried) */
  319.     FAILOSERR(GetCurrentProcess(&me));
  320.     FAILOSERR(SameProcess(&psn, &me, &same));
  321.     if (same)
  322.         return appMemFullErr;            /* This is a lie. So what ? */
  323.     
  324.     /* Build shell wrapper for command string */
  325.     FAILOSERR(PtrToHand(BEGIN_TEXT, &text, strlen(BEGIN_TEXT)));
  326.     FAILOSERR(Path2FSSpec(":", &vol));
  327.     segment    =    FSp2FullPath(&vol);
  328.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  329.     FAILOSERR(PtrAndHand(DIRSET_TEXT, text, strlen(DIRSET_TEXT)));
  330.     FAILOSERR(PtrAndHand(commandline, text, strlen(commandline)));
  331.     FAILOSERR(PtrAndHand(END_TEXT, text, strlen(END_TEXT)));
  332.     DEVSTRING(input);
  333.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  334.     FAILOSERR(PtrAndHand(STDOUT_TEXT, text, strlen(STDOUT_TEXT)));
  335.     DEVSTRING(output);
  336.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  337.     FAILOSERR(PtrAndHand(STDERR_TEXT, text, strlen(STDERR_TEXT)));
  338.     DEVSTRING(error);
  339.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  340.     FAILOSERR(PtrAndHand(TERM_TEXT, text, strlen(TERM_TEXT)));
  341.     
  342.     /* Build the AppleEvent */
  343.     FAILOSERR(
  344.         AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(psn), &addr));
  345.     FAILOSERR(
  346.         AECreateAppleEvent('misc', 'dosc', &addr, 
  347.             kAutoGenerateReturnID, kAnyTransactionID, 
  348.             &cmd));
  349.     HLock(text);
  350.     FAILOSERR(
  351.         AEPutParamPtr(&cmd, '----', typeChar, *text, GetHandleSize(text)));
  352.     DisposHandle(text);
  353.     
  354.     /* Send it */
  355.     acur    =    (acurHandle) GetResource('acur', 128);
  356.     DetachResource((Handle) acur);
  357.     InitCursorCtl(acur);
  358.     err    =    
  359.         AESend(
  360.             &cmd, &reply, kAEWaitReply+kAENeverInteract, 
  361.             kAENormalPriority, kNoTimeOut, 
  362.             (IdleProcPtr) SubLaunchIdle, nil);
  363.         
  364.     AEDisposeDesc(&cmd);
  365.     AEDisposeDesc(&addr);
  366.     AEDisposeDesc(&reply);
  367.     
  368.     ReleaseResource((Handle) acur);
  369.     
  370.     InitCursorCtl(NULL);
  371.     
  372.     return err;
  373. }
  374.  
  375.  
  376.